﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;

namespace Library.BallRelationHMM
{
    public class HMMPreprocessor
    {
        public void PrintInstances(string fileName)
        {
            var fileLines = File.ReadAllLines(fileName);
            var numLines = fileLines.Length;
            IList<int> relatedLineNumbers = new List<int>();
            
            for (int i = 0; i < numLines - 1; i++)
            {
                if (string.IsNullOrWhiteSpace(fileLines[i]))
                {
                    continue;
                }

                string []words;
                if (fileLines[i].IndexOf("end of over", StringComparison.OrdinalIgnoreCase) > 0)
                {
                    words = fileLines[i].Substring(0, fileLines[i].IndexOf("end of over", StringComparison.OrdinalIgnoreCase)).Split(' ', '\t');                    
                }
                else
                {
                    words = fileLines[i].Split(' ', '\t');
                }              
                
                var presentLineOver = Convert.ToDouble(words[0]);
                var nextLineOver = Convert.ToDouble(fileLines[i + 1].Substring(0, fileLines[i + 1].IndexOf(' ')));
                if (nextLineOver > presentLineOver && nextLineOver - presentLineOver < 1)
                {
                    relatedLineNumbers.Add(i);
                    relatedLineNumbers.Add(i + 1);
                }                        
                                   

            }

            var relatedDirectory = Path.Combine(Path.GetDirectoryName(fileName), "RelatedDeliveries");
            if(!Directory.Exists(relatedDirectory))
            {
                Directory.CreateDirectory(relatedDirectory);
            }

            StreamWriter sw = new StreamWriter(Path.Combine(relatedDirectory, Path.GetFileNameWithoutExtension(fileName) + "_related.txt"));

            foreach (var lineNumber in relatedLineNumbers)
            {
                if (fileLines[lineNumber].IndexOf("end of over", StringComparison.OrdinalIgnoreCase) > 0)
                {
                    sw.WriteLine(fileLines[lineNumber].Substring(0, fileLines[lineNumber].IndexOf("end of over", StringComparison.OrdinalIgnoreCase)));
                }
                else
                {
                    sw.WriteLine(fileLines[lineNumber]);
                }
            }
            sw.Close();
        }

        public static void FormatRelationalInstancesWithRuns(string fileName)
        {
            float[,] emissionOccurrences = new float[6, 9]; // Likelihood
            float[,] transitionOccurrences = new float[6, 6];    //Transition
            
            try
            {               
                var fileLines = File.ReadAllLines(fileName);
                var numLines = fileLines.Length;
                for (int i = 0; i < numLines - 1; i += 2)
                {
                    if (fileLines[i].IndexOf("No Info") >= 0 || fileLines[i + 1].IndexOf("No Info") >= 0)
                    {                        
                        continue;
                    }
                    int runsFirst = ProcessEmisisonTransition(fileLines[i], emissionOccurrences, true);
                    int runsSecond = 0;

                    if (i + 2 < numLines && string.CompareOrdinal(fileLines[i + 1], fileLines[i + 2]) == 0)
                    {
                        runsSecond = ProcessEmisisonTransition(fileLines[i + 1], emissionOccurrences, false);
                    }
                    else
                    {
                        runsSecond = ProcessEmisisonTransition(fileLines[i + 1], emissionOccurrences, true);
                    }
                    transitionOccurrences[runsFirst, runsSecond]++;                    
                }

                float[] startProbability = new float[6];

                float totalSum = 0;
                for (int i = 0; i < 6; i++)
                { 
                    for (int j = 0; j < 9; j++)
                    {
                        totalSum += emissionOccurrences[i, j];
                    }
                }

                for (int i = 0; i < 6; i++)
                {
                    float rowSum = 0;
                    for (int j = 0; j < 9; j++)
                    {
                        rowSum += emissionOccurrences[i, j];
                    }
                    startProbability[i] = rowSum / totalSum;

                }
                Console.WriteLine("Start Probabilities:");
                for (int i = 0; i < 6; i++)
                {
                    Console.Write(startProbability[i] + "\t");                 
                }

                Console.WriteLine("Transition Occurrences :\n");
                for (int i = 0; i < 6; i++)
                {
                    float sum = 0;
                    for (int j = 0; j < 6; j++)
                    {
                        Console.Write(transitionOccurrences[i, j] + "\t");
                        sum += transitionOccurrences[i, j];
                    }

                    for (int j = 0; j < 6; j++)
                    {
                        if (sum > 0)
                        {
                            transitionOccurrences[i, j] = transitionOccurrences[i, j] / sum;
                        }
                        else
                        {
                            transitionOccurrences[i, j] = (float) 1/6;
                        }
                    }
                    Console.WriteLine();
                }

                Console.WriteLine("Transition Probabilities:");
                for (int i = 0; i < 6; i++)
                {                    
                    for (int j = 0; j < 6; j++)
                    {
                        Console.Write(transitionOccurrences[i, j] + "\t");                    
                    }

                    Console.WriteLine();
                }

                Console.WriteLine("Emission Occurrences :\n");
                for (int i = 0; i < 6; i++)
                {
                    float sum = 0;
                    for (int j = 0; j < 9; j++)
                    {
                        Console.Write(emissionOccurrences[i, j] + "\t");
                        sum += emissionOccurrences[i, j];
                    }

                    for (int j = 0; j < 9; j++)
                    {
                        if (sum > 0)
                        {
                            emissionOccurrences[i, j] = emissionOccurrences[i, j] / sum;
                        }
                        else
                        {
                            emissionOccurrences[i, j] = (float) 1 / 9;
                        }
                    }
                    Console.WriteLine();
                }

                Console.WriteLine("Emission Probabilities:");
                for (int i = 0; i < 6; i++)
                {
                    for (int j = 0; j < 9; j++)
                    {
                        Console.Write(emissionOccurrences[i, j] + "\t");
                    }

                    Console.WriteLine();
                }

            }
            catch (FileNotFoundException)
            {
                Trace.WriteLine("File Not found!");
            }
        }

        public static void FormatRelationalInstancesWithBatsmanPlay(string fileName)
        {
            float[,] emissionOccurrences = new float[3, 9]; // Likelihood
            float[,] transitionOccurrences = new float[3, 3];    //Transition

            try
            {
                var fileLines = File.ReadAllLines(fileName);
                var numLines = fileLines.Length;
                for (int i = 0; i < numLines - 1; i += 2)
                {
                    if (fileLines[i].IndexOf("No Info") >= 0 || fileLines[i + 1].IndexOf("No Info") >= 0)
                    {
                        continue;
                    }
                    int runsFirst = ProcessEmisisonTransition(fileLines[i], emissionOccurrences, true);
                    int runsSecond = 0;

                    if (i + 2 < numLines && string.CompareOrdinal(fileLines[i + 1], fileLines[i + 2]) == 0)
                    {
                        runsSecond = ProcessEmisisonTransition(fileLines[i + 1], emissionOccurrences, false);
                    }
                    else
                    {
                        runsSecond = ProcessEmisisonTransition(fileLines[i + 1], emissionOccurrences, true);
                    }
                    transitionOccurrences[runsFirst, runsSecond]++;
                }

                float[] startProbability = new float[6];

                float totalSum = 0;
                for (int i = 0; i < 3; i++)
                {
                    for (int j = 0; j < 9; j++)
                    {
                        totalSum += emissionOccurrences[i, j];
                    }
                }

                for (int i = 0; i < 3; i++)
                {
                    float rowSum = 0;
                    for (int j = 0; j < 9; j++)
                    {
                        rowSum += emissionOccurrences[i, j];
                    }
                    startProbability[i] = rowSum / totalSum;

                }
                Console.WriteLine("Start Probabilities:");
                for (int i = 0; i < 3; i++)
                {
                    Console.Write(startProbability[i] + "\t");
                }

                Console.WriteLine("Transition Occurrences :\n");
                for (int i = 0; i < 3; i++)
                {
                    float sum = 0;
                    for (int j = 0; j < 3; j++)
                    {
                        Console.Write(transitionOccurrences[i, j] + "\t");
                        sum += transitionOccurrences[i, j];
                    }

                    for (int j = 0; j < 3; j++)
                    {
                        if (sum > 0)
                        {
                            transitionOccurrences[i, j] = transitionOccurrences[i, j] / sum;
                        }
                        else
                        {
                            transitionOccurrences[i, j] = (float)1 / 6;
                        }
                    }
                    Console.WriteLine();
                }

                Console.WriteLine("Transition Probabilities:");
                for (int i = 0; i < 3; i++)
                {
                    for (int j = 0; j < 3; j++)
                    {
                        Console.Write(transitionOccurrences[i, j] + "\t");
                    }

                    Console.WriteLine();
                }

                Console.WriteLine("Emission Occurrences :\n");
                for (int i = 0; i < 3; i++)
                {
                    float sum = 0;
                    for (int j = 0; j < 9; j++)
                    {
                        Console.Write(emissionOccurrences[i, j] + "\t");
                        sum += emissionOccurrences[i, j];
                    }

                    for (int j = 0; j < 9; j++)
                    {
                        if (sum > 0)
                        {
                            emissionOccurrences[i, j] = emissionOccurrences[i, j] / sum;
                        }
                        else
                        {
                            emissionOccurrences[i, j] = (float)1 / 9;
                        }
                    }
                    Console.WriteLine();
                }

                Console.WriteLine("Emission Probabilities:");
                for (int i = 0; i < 3; i++)
                {
                    for (int j = 0; j < 9; j++)
                    {
                        Console.Write(emissionOccurrences[i, j] + "\t");
                    }

                    Console.WriteLine();
                }

            }
            catch (FileNotFoundException)
            {
                Trace.WriteLine("File Not found!");
            }
        }


        private static int ProcessEmisisonTransition(string fileLine, float [,] emissionOccurences, bool AddToEmissionOccurence)
        {
            int skip = 1, featureScore = 0;

            
            if (fileLine.IndexOf("short") >= 0)
            {
                featureScore = featureScore + 10;
                skip = skip + "short".Length;
            }
            else if (fileLine.IndexOf("full") >= 0)
            {
                featureScore = featureScore + 20;
                skip = skip + "full".Length;
            }
            else if (fileLine.IndexOf("good-length") >= 0)
            {
                featureScore = featureScore + 30;
                skip = skip + "good-length".Length;
            }

            if (fileLine.IndexOf("outside off") >= 0)
            {
                featureScore = featureScore + 1;
                skip = skip + "outside off".Length;
            }
            else if (fileLine.IndexOf("middle stump") >= 0)
            {
                featureScore = featureScore + 2;
                skip = skip + "middle stump".Length;
            }
            else if (fileLine.IndexOf("leg stump") >= 0)
            {
                featureScore = featureScore + 3;
                skip = skip + "leg stump".Length;
            }

            string batsmanPlay  = fileLine.Substring(skip + 1);

            int runs = -1;
            if (string.Compare(batsmanPlay, "Beaten", StringComparison.OrdinalIgnoreCase) == 0)
            {
                runs = 0;
            }
            else if (string.Compare(batsmanPlay, "Defended", StringComparison.OrdinalIgnoreCase) == 0)
            {
                runs = 1;
            }
            else if (string.Compare(batsmanPlay, "Attacked", StringComparison.OrdinalIgnoreCase) == 0)
            {
                runs = 2;
            }
            if (AddToEmissionOccurence)
            {
                int featureIndex = 3 * (featureScore / 10 - 1) + (featureScore % 10 - 1);
                
                emissionOccurences[runs, featureIndex]++;
            }
            
            return runs;
        }
    }
}
